package com.zenithmind.document.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.common.context.UserContext;
import com.zenithmind.document.mapper.DocumentShareMapper;
import com.zenithmind.document.pojo.domain.DocumentShare;
import com.zenithmind.document.pojo.dto.DocumentShareCreateDTO;
import com.zenithmind.document.pojo.dto.DocumentShareUpdateDTO;
import com.zenithmind.document.pojo.query.DocumentShareQueryDTO;
import com.zenithmind.document.pojo.vo.DocumentShareVO;
import com.zenithmind.document.service.DocumentShareService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 文档分享服务实现类
 * 遵循单一职责原则：专注于文档分享功能
 * 遵循依赖倒置原则：依赖抽象接口而不是具体实现
 * 遵循封装原则：通过方法控制分享状态和权限
 * 
 * @author ZenithMind Team
 * @since 2025-01-09
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DocumentShareServiceImpl extends ServiceImpl<DocumentShareMapper, DocumentShare> implements DocumentShareService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DocumentShareVO createShare(DocumentShareCreateDTO createDTO) {
        log.info("创建文档分享: documentId={}", createDTO.getDocumentId());
        
        DocumentShare share;
        if (createDTO.getShareType() == DocumentShare.ShareType.PASSWORD_PROTECTED.getCode()) {
            share = DocumentShare.createPasswordProtected(
                createDTO.getDocumentId(),
                createDTO.getTitle(),
                createDTO.getAccessPassword(),
                UserContext.getUserId()
            );
        } else {
            share = DocumentShare.createPublic(
                createDTO.getDocumentId(),
                createDTO.getTitle(),
                UserContext.getUserId()
            );
        }
        
        // 设置其他属性
        if (createDTO.getDescription() != null) {
            share.setDescription(createDTO.getDescription());
        }
        if (createDTO.getExpireTime() != null) {
            share.setExpireTime(createDTO.getExpireTime());
        }
        if (createDTO.getMaxAccessCount() != null) {
            share.setMaxAccessCount(createDTO.getMaxAccessCount());
        }
        if (createDTO.getPermission() != null) {
            share.setPermission(createDTO.getPermission());
        }
        
        // 生成分享链接
        share.setShareUrl(generateShareUrl(share.getShareCode()));
        
        save(share);
        
        return convertToVO(share);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateShare(String id, DocumentShareUpdateDTO updateDTO) {
        log.info("更新文档分享: id={}", id);
        
        DocumentShare share = getById(id);
        if (share == null) {
            throw new RuntimeException("分享不存在");
        }
        
        // 验证权限
        if (!UserContext.getUserId().equals(share.getSharerId())) {
            throw new RuntimeException("无权限修改此分享");
        }
        
        BeanUtils.copyProperties(updateDTO, share);
        
        return updateById(share);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteShare(String id) {
        log.info("删除文档分享: id={}", id);
        
        DocumentShare share = getById(id);
        if (share == null) {
            throw new RuntimeException("分享不存在");
        }
        
        // 验证权限
        if (!UserContext.getUserId().equals(share.getSharerId())) {
            throw new RuntimeException("无权限删除此分享");
        }
        
        share.disable();
        
        return updateById(share);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchDeleteShares(List<String> ids) {
        log.info("批量删除文档分享: ids={}", ids);
        
        String userId = UserContext.getUserId();
        
        // 验证权限
        for (String id : ids) {
            DocumentShare share = getById(id);
            if (share != null && !userId.equals(share.getSharerId())) {
                throw new RuntimeException("无权限删除分享: " + id);
            }
        }
        
        // 实现批量禁用分享逻辑
        try {
            // 1. 验证所有分享的权限
            for (String id : ids) {
                DocumentShare share = getById(id);
                if (share != null && !userId.equals(share.getSharerId())) {
                    throw new RuntimeException("无权限禁用分享: " + id);
                }
            }

            // 2. 批量更新分享状态
            boolean updateResult = update(new com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper<DocumentShare>()
                .in("id", ids)
                .set("status", 0)
                .set("updater_id", userId)
                .set("update_time", java.time.LocalDateTime.now()));

            // 3. 记录禁用操作日志
            if (updateResult) {
                recordBatchDisableOperation(ids, userId);
            }

            log.info("批量禁用分享完成: ids={}, userId={}, result={}", ids, userId, updateResult);
            return updateResult;

        } catch (Exception e) {
            log.error("批量禁用分享失败: ids={}, userId={}", ids, userId, e);
            throw new RuntimeException("批量禁用分享失败: " + e.getMessage());
        }
    }

    @Override
    public IPage<DocumentShareVO> getSharePage(DocumentShareQueryDTO queryDTO) {
        log.info("分页查询文档分享");
        
        Page<DocumentShareVO> page = new Page<>(queryDTO.getCurrent(), queryDTO.getSize());
        String userId = UserContext.getUserId();
        
        // 修复方法参数不匹配问题 - 实现完整的分页查询逻辑
        try {
            // 构建查询条件
            com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<DocumentShare> wrapper =
                new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<>();

            // 基础条件：只查询当前用户的分享
            wrapper.eq("creator_id", userId);

            // 动态查询条件（根据queryDTO的实际字段调整）
            // 这里假设queryDTO有这些字段，实际需要根据DTO定义调整

            // 排序
            wrapper.orderByDesc("create_time");

            // 执行分页查询
            Page<DocumentShare> sharePage = new Page<>(queryDTO.getCurrent(), queryDTO.getSize());
            IPage<DocumentShare> sharePages = page(sharePage, wrapper);

            // 转换为VO并补充额外信息
            List<DocumentShareVO> voList = sharePages.getRecords().stream()
                .map(this::convertToVO)
                .collect(java.util.stream.Collectors.toList());

            // 构建结果
            Page<DocumentShareVO> result = new Page<>(page.getCurrent(), page.getSize(), sharePages.getTotal());
            result.setRecords(voList);

            log.info("分页查询分享完成: userId={}, total={}", userId, sharePages.getTotal());
            return result;

        } catch (Exception e) {
            log.error("分页查询分享失败: userId={}", userId, e);
            throw new RuntimeException("分页查询分享失败: " + e.getMessage());
        }
    }

    @Override
    public DocumentShareVO getShareDetail(String id) {
        log.info("获取分享详情: id={}", id);
        
        DocumentShare share = getById(id);
        if (share == null) {
            return null;
        }
        
        return convertToVO(share);
    }

    @Override
    public DocumentShareVO getShareByCode(String shareCode) {
        log.info("根据分享码获取分享信息: shareCode={}", shareCode);
        
        return baseMapper.selectShareByCode(shareCode);
    }

    @Override
    public List<DocumentShareVO> getDocumentShares(String documentId, Boolean includeExpired) {
        log.info("获取文档分享列表: documentId={}, includeExpired={}", documentId, includeExpired);
        
        return baseMapper.selectDocumentShares(documentId, includeExpired);
    }

    @Override
    public List<DocumentShareVO> getUserShares(String sharerId, Integer limit) {
        log.info("获取用户分享列表: sharerId={}", sharerId);
        
        return baseMapper.selectUserShares(sharerId, limit);
    }

    @Override
    public List<DocumentShareVO> searchShares(String keyword, Integer limit) {
        log.info("搜索分享: keyword={}", keyword);
        
        return baseMapper.searchShares(keyword, limit);
    }

    @Override
    public List<DocumentShareVO> getHotShares(Integer limit) {
        log.info("获取热门分享");
        
        return baseMapper.selectHotShares(limit);
    }

    @Override
    public Boolean validateShareAccess(String shareCode, String password) {
        log.info("验证分享访问权限: shareCode={}", shareCode);
        
        // 实现根据分享码查询分享记录
        DocumentShare share = getOne(new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<DocumentShare>()
            .eq("share_code", shareCode)
            .eq("status", 1)); // 只查询有效的分享
        if (share == null) {
            log.warn("分享不存在: shareCode={}", shareCode);
            return false;
        }
        
        return share.canAccess() && share.validatePassword(password);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DocumentShareVO accessShare(String shareCode, String password, String userId) {
        log.info("访问分享: shareCode={}, userId={}", shareCode, userId);
        
        // 实现根据分享码查询分享记录
        DocumentShare share = getOne(new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<DocumentShare>()
            .eq("share_code", shareCode)
            .eq("status", 1)); // 只查询有效的分享
        if (share == null) {
            throw new RuntimeException("分享不存在或已失效");
        }
        
        if (!share.canAccess()) {
            throw new RuntimeException("分享已过期或已禁用");
        }
        
        if (!share.validatePassword(password)) {
            throw new RuntimeException("密码错误");
        }
        
        // 记录访问
        share.recordAccess();
        updateById(share);
        
        // 记录访问日志
        recordShareAccess(share.getId(), "view", userId);
        
        return convertToVO(share);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public byte[] downloadSharedDocument(String shareCode, String password, String userId) {
        log.info("下载分享文档: shareCode={}, userId={}", shareCode, userId);
        
        // 实现根据分享码查询分享记录
        DocumentShare share = getOne(new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<DocumentShare>()
            .eq("share_code", shareCode)
            .eq("status", 1)); // 只查询有效的分享
        if (share == null) {
            throw new RuntimeException("分享不存在或已失效");
        }
        
        if (!share.canAccess()) {
            throw new RuntimeException("分享已过期或已禁用");
        }
        
        if (!share.validatePassword(password)) {
            throw new RuntimeException("密码错误");
        }
        
        // 检查下载权限
        if (share.getSharePermissionEnum() == DocumentShare.SharePermission.VIEW_ONLY) {
            throw new RuntimeException("此分享不允许下载");
        }
        
        // 记录下载
        share.recordDownload();
        updateById(share);
        
        // 记录访问日志
        recordShareAccess(share.getId(), "download", userId);
        
        // 实现文件下载逻辑
        try {
            // 获取文档信息
            String documentId = share.getDocumentId();

            // 这里应该调用文档服务获取文档信息
            // Document document = documentService.getById(documentId);

            // 模拟文件下载
            log.info("下载分享文档文件: documentId={}, shareId={}", documentId, share.getId());

            // TODO: 实现真实的文件下载逻辑
            // 1. 获取文档文件路径
            // 2. 从存储系统读取文件
            // 3. 返回文件字节数组

            return new byte[0]; // 临时返回空数组

        } catch (Exception e) {
            log.error("分享文档文件下载失败: shareCode={}", shareCode, e);
            throw new RuntimeException("文件下载失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean recordShareAccess(String shareId, String accessType, String userId) {
        log.info("记录分享访问: shareId={}, accessType={}, userId={}", shareId, accessType, userId);
        
        // 实现分享访问记录逻辑
        try {
            // 创建分享访问记录
            ShareAccessRecord record = new ShareAccessRecord();
            record.setShareId(shareId);
            record.setAccessType(accessType);
            record.setUserId(userId);
            record.setAccessTime(java.time.LocalDateTime.now());
            record.setIpAddress(getCurrentUserIpAddress());
            record.setUserAgent(getCurrentUserAgent());

            // 保存访问记录
            saveShareAccessRecord(record);

            // 更新分享统计信息
            updateShareStatistics(shareId, accessType);

            log.debug("分享访问记录保存成功: shareId={}, accessType={}, userId={}", shareId, accessType, userId);
            return true;

        } catch (Exception e) {
            log.error("记录分享访问失败: shareId={}, accessType={}, userId={}", shareId, accessType, userId, e);
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DocumentShareVO copyShare(String sourceShareId, String newTitle) {
        log.info("复制分享: sourceShareId={}, newTitle={}", sourceShareId, newTitle);
        
        DocumentShare sourceShare = getById(sourceShareId);
        if (sourceShare == null) {
            throw new RuntimeException("源分享不存在");
        }
        
        // 验证权限
        if (!UserContext.getUserId().equals(sourceShare.getSharerId())) {
            throw new RuntimeException("无权限复制此分享");
        }
        
        // 创建新分享
        DocumentShare newShare = DocumentShare.createPublic(
            sourceShare.getDocumentId(),
            newTitle,
            UserContext.getUserId()
        );
        
        // 复制属性
        newShare.setDescription(sourceShare.getDescription());
        newShare.setShareType(sourceShare.getShareType());
        newShare.setPermission(sourceShare.getPermission());
        newShare.setExpireTime(sourceShare.getExpireTime());
        newShare.setMaxAccessCount(sourceShare.getMaxAccessCount());
        newShare.setAccessPassword(sourceShare.getAccessPassword());
        
        // 生成新的分享码和链接
        newShare.generateShareCode();
        newShare.setShareUrl(generateShareUrl(newShare.getShareCode()));
        
        save(newShare);
        
        return convertToVO(newShare);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean disableDocumentShares(String documentId) {
        log.info("禁用文档的所有分享: documentId={}", documentId);
        
        return baseMapper.disableDocumentShares(documentId) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateExpiredShares() {
        log.info("更新过期分享状态");
        
        // 实现过期分享更新逻辑
        try {
            java.time.LocalDateTime now = java.time.LocalDateTime.now();

            // 查找所有过期的分享
            com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper<DocumentShare> wrapper =
                new com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper<>();

            wrapper.eq("status", 1) // 只更新有效的分享
                   .lt("expire_time", now) // 过期时间小于当前时间
                   .set("status", 0) // 设置为无效
                   .set("update_time", now);

            // 执行批量更新
            boolean updateResult = update(wrapper);

            // 统计更新的数量
            int updatedCount = 0;
            if (updateResult) {
                // 查询刚才更新的记录数量
                updatedCount = (int) count(new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<DocumentShare>()
                    .eq("status", 0)
                    .lt("expire_time", now)
                    .ge("update_time", now.minusMinutes(1))); // 最近1分钟更新的
            }

            log.info("过期分享更新完成: updatedCount={}", updatedCount);
            return updatedCount;

        } catch (Exception e) {
            log.error("更新过期分享失败", e);
            return 0;
        }
    }

    @Override
    public DocumentShareVO getShareStatistics(String shareId) {
        log.info("获取分享统计信息: shareId={}", shareId);
        
        return baseMapper.selectShareStatistics(shareId);
    }

    @Override
    public List<Object> getShareAccessLogs(String shareId, Integer limit) {
        log.info("获取分享访问记录: shareId={}", shareId);
        
        return baseMapper.selectShareAccessLogs(shareId, limit);
    }

    @Override
    public String generateShareUrl(String shareCode) {
        // 从配置中获取域名
        String baseUrl = getShareBaseUrl();
        return baseUrl + "/" + shareCode;
    }

    @Override
    public Boolean checkShareCodeExists(String shareCode, String excludeId) {
        log.info("检查分享码是否存在: shareCode={}, excludeId={}", shareCode, excludeId);
        
        return baseMapper.checkShareCodeExists(shareCode, excludeId);
    }

    /**
     * 转换为VO
     */
    private DocumentShareVO convertToVO(DocumentShare share) {
        DocumentShareVO vo = new DocumentShareVO();
        BeanUtils.copyProperties(share, vo);
        
        // 设置类型名称
        if (share.getShareTypeEnum() != null) {
            vo.setShareTypeName(share.getShareTypeEnum().getDescription());
        }
        
        // 设置权限名称
        if (share.getSharePermissionEnum() != null) {
            vo.setPermissionName(share.getSharePermissionEnum().getDescription());
        }
        
        // 设置状态信息
        vo.setCanAccess(share.canAccess());
        vo.setIsExpired(share.isExpired());
        vo.setIsAccessLimitReached(share.isAccessLimitReached());
        vo.setIsPopular(share.isPopular());
        
        return vo;
    }

    // ========== 私有辅助方法 ==========

    /**
     * 记录批量禁用操作
     */
    private void recordBatchDisableOperation(java.util.List<String> ids, String userId) {
        // TODO: 实现批量禁用操作记录
        log.info("记录批量禁用分享操作: ids={}, userId={}", ids, userId);
    }

    /**
     * 获取当前用户IP地址
     */
    private String getCurrentUserIpAddress() {
        // TODO: 实现获取当前用户IP地址
        return "127.0.0.1";
    }

    /**
     * 获取当前用户代理
     */
    private String getCurrentUserAgent() {
        // TODO: 实现获取当前用户代理
        return "Unknown";
    }

    /**
     * 保存分享访问记录
     */
    private void saveShareAccessRecord(ShareAccessRecord record) {
        // TODO: 实现保存分享访问记录到数据库
        log.info("保存分享访问记录: {}", record);
    }

    /**
     * 更新分享统计信息
     */
    private void updateShareStatistics(String shareId, String accessType) {
        // TODO: 实现更新分享统计信息
        log.debug("更新分享统计信息: shareId={}, accessType={}", shareId, accessType);
    }

    /**
     * 获取分享基础URL
     */
    private String getShareBaseUrl() {
        // TODO: 从配置文件或环境变量中获取分享基础URL
        // 这里应该从application.yml或环境变量中读取
        return "https://example.com/share";
    }

    /**
     * 分享访问记录内部类
     */
    private static class ShareAccessRecord {
        private String shareId;
        private String accessType;
        private String userId;
        private java.time.LocalDateTime accessTime;
        private String ipAddress;
        private String userAgent;

        // Getters and Setters
        public String getShareId() { return shareId; }
        public void setShareId(String shareId) { this.shareId = shareId; }

        public String getAccessType() { return accessType; }
        public void setAccessType(String accessType) { this.accessType = accessType; }

        public String getUserId() { return userId; }
        public void setUserId(String userId) { this.userId = userId; }

        public java.time.LocalDateTime getAccessTime() { return accessTime; }
        public void setAccessTime(java.time.LocalDateTime accessTime) { this.accessTime = accessTime; }

        public String getIpAddress() { return ipAddress; }
        public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }

        public String getUserAgent() { return userAgent; }
        public void setUserAgent(String userAgent) { this.userAgent = userAgent; }

        @Override
        public String toString() {
            return "ShareAccessRecord{" +
                    "shareId='" + shareId + '\'' +
                    ", accessType='" + accessType + '\'' +
                    ", userId='" + userId + '\'' +
                    ", accessTime=" + accessTime +
                    ", ipAddress='" + ipAddress + '\'' +
                    ", userAgent='" + userAgent + '\'' +
                    '}';
        }
    }
}
